/*
 * Created on Apr 17, 2010
 *
 * TODO 
 */
package jacky.lanlan.song.extension.vraptor2;

import java.io.IOException;
import java.io.OutputStream;

import org.vraptor.Interceptor;
import org.vraptor.LogicDefinition;
import org.vraptor.LogicException;
import org.vraptor.LogicFlow;
import org.vraptor.component.LogicMethod;
import org.vraptor.http.VRaptorServletResponse;
import org.vraptor.view.ViewException;

public abstract class BaseInterceptor implements Interceptor {

	@Override
	public final void intercept(LogicFlow flow) throws LogicException, ViewException {
		if (canIntercept(getLogicMethod(flow)))
			doIntercept(flow);
		else
			flow.execute();// 放行
	}

	public static LogicDefinition getLogicDefinition(LogicFlow flow) {
		return flow.getLogicRequest().getLogicDefinition();
	}

	public static VRaptorServletResponse getResponse(LogicFlow flow) {
		return flow.getLogicRequest().getResponse();
	}

	public static LogicMethod getLogicMethod(LogicFlow flow) {
		return getLogicDefinition(flow).getLogicMethod();
	}

	/**
	 * 通过反射调用Logic方法直接得到返回值，而不通过LogicMethod.execute()，因为这个方法会把返回值变成String
	 * <p>
	 * <b style="color:red">需要 ComponentLookupInterceptor 和 SettingAndValidationInterceptor 配合，否则不能使用！</b>
	 * 
	 * @param flow
	 *          本次请求的 LogicFlow
	 * @return 直接调用方法后的返回值
	 * @throws Exception
	 */
	public static Object invokeLogicMethod(LogicFlow flow) throws Exception {
		LogicDefinition define = getLogicDefinition(flow);
		/*
		 * 这里，需要 ComponentLookupInterceptor 提供 Component 实例，否则define.getComponent()返回null 需要
		 * SettingAndValidationInterceptor 提供 方法参数，否则define.getParameters()返回空数组[]
		 */
		return getLogicMethod(flow).getMetadata().invoke(define.getComponent(), define.getParameters());

	}

	/**
	 * 是否拦截该 {@code LogicMethod} 。
	 */
	protected abstract boolean canIntercept(LogicMethod logic);

	/**
	 * 执行具体的拦截逻辑。
	 * 
	 * @param flow
	 *          同 {@code Interceptor.intercept()} 方法的参数
	 */
	protected abstract void doIntercept(LogicFlow flow) throws LogicException, ViewException;

	public static void close(OutputStream os) {
		try {
			if (os != null) os.close();
		}
		catch (IOException ioe) {
		}
	}

	public static void writeAndClose(byte[] data, OutputStream out) throws IOException {
		if (data == null) return;

		try {
			out.write(data);
		}
		finally {
			close(out);
		}
	}

}
